# -*- coding: utf-8 -*-
'''
Created on 25/01/2013

@author: pln
'''

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import sys
import platform

class RichTextLineEdit(QTextEdit):

    (Bold, Italic, Underline, StrikeOut, Monospaced, Sans, Serif,
     NoSuperOrSubscript, Subscript, Superscript) = range(10)

    # inicialização dos atributos da classe RichTextLineEdit
    def __init__(self, parent=None):
        super(RichTextLineEdit, self).__init__(parent)

        self.monofamily = QString("courier")
        self.sansfamily = QString("helvetica")
        self.seriffamily = QString("times")
        self.setLineWrapMode(QTextEdit.NoWrap)
        self.setTabChangesFocus(True)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        fm = QFontMetrics(self.font())
        h = int(fm.height() * (1.4 if platform.system() == "Windows" else 1.2))
        self.setMinimumHeight(h)
        self.setMaximumHeight(int(h * 1.2))
        self.setToolTip("Press <b>Ctrl+M</b> for the text effects " "Menu and <b>Ctrl+K</b> for the color menu")
  
    # explicar o que faz o método toggleItalic, se não estiver utilizando o método comente o código referente ao método
    def toggleItalic(self):
        self.setFontItalic(not self.fontItalic())
        
    # explicar o que faz o método toggleUnderline, se não estiver utilizando o método comente o código referente ao método
    def toggleUnderline(self):
        self.setFontUnderline(not self.fontUnderline())

    # explicar o que faz o método toggleBold, se não estiver utilizando o método comente o código referente ao método    
    def toggleBold(self):
        self.setFontWeight(QFont.Normal \
                if self.fontWeight() > QFont.Normal else QFont.Bold)

    # explicar o que faz o método sizeHint, se não estiver utilizando o método comente o código referente ao método            
    def sizeHint(self):
        return QSize(self.document().idealWidth() + 5,
                     self.maximumHeight())

    # explicar o que faz o método minimumSizeHint, se não estiver utilizando o método comente o código referente ao método
    def minimumSizeHint(self):
        fm = QFontMetrics(self.font())
        return QSize(fm.width("WWW"), self.minimumHeight())

    # explicar o que faz o método contextMenuEvent, se não estiver utilizando o método comente o código referente ao método
    def contextMenuEvent(self, event):
        self.textEffectMenu()
        
    # explicar o que faz o método keyPressEvent, se não estiver utilizando o método comente o código referente ao método
    def keyPressEvent(self, event):
        if event.modifiers() & Qt.ControlModifier:
            handled = False
            if event.key() == Qt.Key_B:
                self.toggleBold()
                handled = True
            elif event.key() == Qt.Key_I:
                self.toggleItalic()
                handled = True
            elif event.key() == Qt.Key_K:
                self.colorMenu()
                handled = True
            elif event.key() == Qt.Key_M:
                self.textEffectMenu()
                handled = True
            elif event.key() == Qt.Key_U:
                self.toggleUnderline()
                handled = True
            if handled:
                event.accept()
                return
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            self.emit(SIGNAL("returnPressed()"))
            event.accept()
        else:
            QTextEdit.keyPressEvent(self, event)

    # explicar o que faz o método colorMenu, se não estiver utilizando o método comente o código referente ao método
    def colorMenu(self):
        pixmap = QPixmap(22, 22)
        menu = QMenu("Colour")
        for text, color in (("Black", Qt.black), ("Blue", Qt.blue), ("Dark Blue", Qt.darkBlue), ("Cyan", Qt.cyan), ("Dark Cyan", Qt.darkCyan), ("Green", Qt.green), ("Dark Green", Qt.darkGreen), ("Magenta", Qt.magenta), ("Dark Magenta", Qt.darkMagenta),("Red", Qt.red), ("Dark Red", Qt.darkRed)):
            color = QColor(color)
            pixmap.fill(color)
            action = menu.addAction(QIcon(pixmap), text, self.setColor)
            action.setData(QVariant(color))
        self.ensureCursorVisible()
        menu.exec_(self.viewport().mapToGlobal(self.cursorRect().center()))

    # explicar o que faz o método setColor, se não estiver utilizando o método comente o código referente ao método
    def setColor(self):
        action = self.sender()
        if action is not None and isinstance(action, QAction):
            color = QColor(action.data())
            if color.isValid():
                self.setTextColor(color)

    # explicar o que faz o método textEffectMenu, se não estiver utilizando o método comente o código referente ao método
    def textEffectMenu(self):
        format = self.currentCharFormat()
        menu = QMenu("Text Effect")
        for text, shortcut, data, checked in (
                ("Bold", "Ctrl+B", RichTextLineEdit.Bold,
                 self.fontWeight() > QFont.Normal),
                ("Italic", "Ctrl+I", RichTextLineEdit.Italic,
                 self.fontItalic()),
                ("Strike out", None, RichTextLineEdit.StrikeOut,
                 format.fontStrikeOut()),
                ("Underline", "Ctrl+U", RichTextLineEdit.Underline,
                 self.fontUnderline()),
                ("Monospaced", None, RichTextLineEdit.Monospaced,
                 format.fontFamily() == self.monofamily),
                ("Serifed", None, RichTextLineEdit.Serif,
                 format.fontFamily() == self.seriffamily),
                ("Sans Serif", None, RichTextLineEdit.Sans,
                 format.fontFamily() == self.sansfamily),
                ("No super or subscript", None,
                 RichTextLineEdit.NoSuperOrSubscript,
                 format.verticalAlignment() == \
                 QTextCharFormat.AlignNormal),
                ("Superscript", None, RichTextLineEdit.Superscript,
                 format.verticalAlignment() == \
                 QTextCharFormat.AlignSuperScript),
                ("Subscript", None, RichTextLineEdit.Subscript,
                 format.verticalAlignment() == \
                 QTextCharFormat.AlignSubScript)):
            action = menu.addAction(text, self.setTextEffect)
            if shortcut is not None:
                action.setShortcut(QKeySequence(shortcut))
            action.setData(QVariant(data))
            action.setCheckable(True)
            action.setChecked(checked)
        self.ensureCursorVisible()
        menu.exec_(self.viewport().mapToGlobal(self.cursorRect().center()))

    # explicar o que faz o método setTextEffect, se não estiver utilizando o método comente o código referente ao método
    def setTextEffect(self):
        action = self.sender()
        if action is not None and isinstance(action, QAction):
            what = action.data().toInt()[0]
            if what == RichTextLineEdit.Bold:
                self.toggleBold()
                return
            if what == RichTextLineEdit.Italic:
                self.toggleItalic()
                return
            if what == RichTextLineEdit.Underline:
                self.toggleUnderline()
                return
            format = self.currentCharFormat()
            if what == RichTextLineEdit.Monospaced:
                format.setFontFamily(self.monofamily)
            elif what == RichTextLineEdit.Serif:
                format.setFontFamily(self.seriffamily)
            elif what == RichTextLineEdit.Sans:
                format.setFontFamily(self.sansfamily)
            if what == RichTextLineEdit.StrikeOut:
                format.setFontStrikeOut(not format.fontStrikeOut())
            if what == RichTextLineEdit.NoSuperOrSubscript:
                format.setVerticalAlignment(
                        QTextCharFormat.AlignNormal)
            elif what == RichTextLineEdit.Superscript:
                format.setVerticalAlignment(
                        QTextCharFormat.AlignSuperScript)
            elif what == RichTextLineEdit.Subscript:
                format.setVerticalAlignment(
                        QTextCharFormat.AlignSubScript)
            self.mergeCurrentCharFormat(format)

    # explicar o que faz o método toSimpleHtml, se não estiver utilizando o método comente o código referente ao método
    def toSimpleHtml(self):
        html = QString()
        black = QColor(Qt.black)
        block = self.document().begin()
        while block.isValid():
            iterator = block.begin()
            while iterator != block.end():
                fragment = iterator.fragment()
                if fragment.isValid():
                    format = fragment.charFormat()
                    family = format.fontFamily()
                    color = format.foreground().color()
                    text = Qt.escape(fragment.text())
                    if format.verticalAlignment() == \
                       QTextCharFormat.AlignSubScript:
                        text = QString("<sub>%1</sub>").arg(text)
                    elif format.verticalAlignment() == \
                        QTextCharFormat.AlignSuperScript:
                        text = QString("<sup>%1</sup>").arg(text)
                    if format.fontUnderline():
                        text = QString("<u>%1</u>").arg(text)
                    if format.fontItalic():
                        text = QString("<i>%1</i>").arg(text)
                    if format.fontWeight() > QFont.Normal:
                        text = QString("<b>%1</b>").arg(text)
                    if format.fontStrikeOut():
                        text = QString("<s>%1</s>").arg(text)
                    if color != black or not family.isEmpty():
                        attribs = ""
                        if color != black:
                            attribs += ' color="%s"' % color.name()
                        if not family.isEmpty():
                            attribs += ' face="%s"' % family
                        text = QString("<font%1>%2</font>").arg(attribs).arg(text)
                    html += text
                iterator += 1
            block = block.next()
        return html

if __name__ == "__main__":
    app = QApplication(sys.argv)
    lineedit = RichTextLineEdit()
    lineedit.show()
    lineedit.setWindowTitle("RichTextEdit")
    app.exec_()
    print unicode(lineedit.toHtml())
    print unicode(lineedit.toPlainText())
    print unicode(lineedit.toSimpleHtml())


